Completed
Pull Request — develop (#75)
by
unknown
01:00
created

forcegraph.js ➔ ... ➔ d3Drag.drag.end   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
c 1
b 0
f 0
nc 2
dl 0
loc 7
rs 9.4285
nop 0
1
define(['d3-selection', 'd3-force', 'd3-zoom', 'd3-drag', 'helper', 'forcegraph/math', 'forcegraph/draw'], function (d3Selection, d3Force, d3Zoom, d3Drag, helper, math, draw) {
2
  'use strict';
3
4
  return function (config, linkScale, sidebar, router) {
5
    var self = this;
6
    var el;
7
    var canvas;
8
    var ctx;
9
    var force;
10
    var forceLink;
11
12
    var transform = d3Zoom.zoomIdentity;
13
    var intNodes = [];
14
    var dictNodes = {};
15
    var intLinks = [];
16
17
    const NODE_RADIUS = 15;
18
    const LINE_RADIUS = 12;
19
20
    draw.setTransform(transform);
21
22
    function resizeCanvas() {
23
      canvas.width = el.offsetWidth;
24
      canvas.height = el.offsetHeight;
25
      canvas.style.width = el.offsetWidth + 'px';
26
      canvas.style.height = el.offsetHeight + 'px';
27
    }
28
29
    function onClick() {
30
      if (d3Selection.event.defaultPrevented) {
31
        return;
32
      }
33
34
      var e = transform.invert([d3Selection.event.clientX, d3Selection.event.clientY]);
35
      var n = force.find(e[0], e[1], NODE_RADIUS);
36
37
      if (n !== undefined) {
38
        router.node(n.o.node)();
39
        return;
40
      }
41
42
      e = {x: e[0], y: e[1]};
43
44
      var links = intLinks
45
        /* Disable Clickable VPN
46
        .filter(function (d) {
47
          return d.o.type !== 'fastd' && d.o.type !== 'L2TP';
48
        })
49
        */
50
        .filter(function (d) {
51
          return math.distanceLink(e, d.source, d.target) < LINE_RADIUS;
52
        });
53
54
      if (links.length > 0) {
55
        router.link(links[0].o)();
56
      }
57
    }
58
59
    function redraw() {
60
      ctx.save();
61
      ctx.clearRect(0, 0, canvas.width, canvas.height);
62
      ctx.translate(transform.x, transform.y);
63
      ctx.scale(transform.k, transform.k);
64
65
      intLinks.forEach(draw.drawLink);
66
      intNodes.forEach(draw.drawNode);
67
68
      ctx.restore();
69
    }
70
71
    el = document.createElement('div');
72
    el.classList.add('graph');
73
74
    forceLink = d3Force.forceLink()
75
     .distance(function (d) {
76
       if (d.o.type === 'fastd' || d.o.type === 'L2TP') {
77
         return 0;
78
       }
79
       return 75;
80
     })
81
     .strength(function (d) {
82
       if (d.o.type === 'fastd' || d.o.type === 'L2TP') {
83
         return 0.02;
84
       }
85
       return Math.max(0.5, 1 / d.o.tq);
86
     });
87
88
    var zoom = d3Zoom.zoom()
89
         .scaleExtent([1 / 3, 3])
90
         .on('zoom', function () {
91
           transform = d3Selection.event.transform;
92
           // draw.setTransform(transform);
93
           redraw();
94
         });
95
96
97
    force = d3Force.forceSimulation()
98
      .force('link', forceLink)
99
      .force('charge', d3Force.forceManyBody())
100
      .on('tick', redraw);
101
102
    var drag = d3Drag.drag()
103
      .subject(function () {
104
        if (!d3Selection.event.active) {
105
          force.alphaTarget(0.1).restart();
106
        }
107
        var e = transform.invert([d3Selection.event.x, d3Selection.event.y]);
108
        var n = force.find(e[0], e[1], NODE_RADIUS);
109
110
        if (n !== undefined) {
111
          n.fx = transform.applyX(n.x);
112
          n.fy = transform.applyY(n.y);
113
          return n;
114
        }
115
        return undefined;
116
      })
117
      .on('drag', function () {
118
        var e = transform.invert([d3Selection.event.x, d3Selection.event.y]);
119
        d3Selection.event.subject.fx = e[0];
120
        d3Selection.event.subject.fy = e[1];
121
      })
122
      .on('end', function () {
123
        if (!d3Selection.event.active) {
124
          d3Selection.event.subject.fx = null;
125
          d3Selection.event.subject.fy = null;
126
          force.alphaTarget(0);
127
        }
128
      });
129
130
    canvas = d3Selection.select(el)
131
      .append('canvas')
132
      .on('click', onClick)
133
      .call(drag)
134
      .call(zoom)
135
      .node();
136
137
    ctx = canvas.getContext('2d');
138
    draw.setCTX(ctx);
139
140
    window.addEventListener('resize', function () {
141
      resizeCanvas();
142
      redraw();
143
    });
144
145
    self.setData = function setData(data) {
146
      intNodes = data.graph.nodes.map(function (d) {
147
        var e;
148
        if (d.id in dictNodes) {
149
          e = dictNodes[d.id];
150
        } else {
151
          e = {};
152
          dictNodes[d.id] = e;
153
        }
154
155
        e.o = d;
156
157
        return e;
158
      });
159
160
      intLinks = data.graph.links.map(function (d) {
161
        var e = {};
162
        e.o = d;
163
        e.source = dictNodes[d.source.id];
164
        e.target = dictNodes[d.target.id];
165
        e.color = linkScale(d.tq).hex();
166
167
        return e;
168
      });
169
170
      force.nodes(intNodes);
171
      forceLink.links(intLinks);
172
173
      force.restart();
174
      resizeCanvas();
175
    };
176
177
    self.resetView = function resetView() {
178
      draw.setHighlight(null);
179
      redraw();
180
    };
181
182
    self.gotoNode = function gotoNode(d) {
183
      draw.setHighlight({ type: 'node', o: d });
184
      redraw();
185
    };
186
187
    self.gotoLink = function gotoLink(d) {
188
      draw.setHighlight({ type: 'link', o: d });
189
      redraw();
190
    };
191
192
    self.destroy = function destroy() {
193
      force.stop();
194
      canvas.remove();
195
      force = null;
196
197
      if (el.parentNode) {
198
        el.parentNode.removeChild(el);
199
      }
200
    };
201
202
    self.render = function render(d) {
203
      d.appendChild(el);
204
      resizeCanvas();
205
    };
206
207
    return self;
208
  };
209
});
210